/************************************************************
 * File: set.cpp
 * Name : Stephen Durfey
 * Class: CS335
 * Due Date: 9/1/2008 
 ************************************************************/

#include <iostream>
#include <cstring>
#include <string>
using namespace std;

// chars are 8-bit, meaning there can only be 256 of them
const int NUMBER_OF_UNIQUE_CHARS = 256;

////////////////////////////////////////////////////////////
//
//  Charset represents a SET Datatype that holds characters 
//  A SET has no specified order and no duplicate values
//  Often, a SET will let you do unions and intersections
//   (But not this one)
//
////////////////////////////////////////////////////////////
class CharSet {
public:
	
	// constructors initializes the set to empty
	CharSet() {
		for (int i = 0; i < NUMBER_OF_UNIQUE_CHARS; i++)
			isInSet[i] = false;
	}
	
	// put a specific character into the set
	// if the character is already in the set, no change
	void insert(char c)
        {
            int index = indexFromChar(c);
            if(!isInSet[index])
                isInSet[index] = true;
	}
	
	// check if a specific character in in the set
	bool isMember(char c)
        {
            int index = indexFromChar(c);
            if(isInSet[index])
                return true;
            else
                return false;
           
	}
	
	// remove a character from the set
	// if the character is not in the set, no change
	void remove(char c) 
        {
            int index = indexFromChar(c);
            if(isInSet[index])
                isInSet[index] = false;
	}
	
	// insert a null-terminated (c-string) of characters
	//  into the set
	void insert(const char chars[])
        {
            int index = 0, charIndex;
            
            while(chars[index] != '\0')
            {
                charIndex = indexFromChar(chars[index]);
                
                if(!isInSet[charIndex])
                    isInSet[charIndex] = true;
                index++;
            }
        }
	
	// return a string containing all of the characters in
	//  this set in ASCII-value order
	// note: this will act funny with non-printable characters
	string toString() 
        {
            string charString = "";
            
            for(int index = 0; index < NUMBER_OF_UNIQUE_CHARS; index++)
            {
                if(isInSet[index])
                    charString += charFromIndex(index);
            }
            
            return charString;
	}
	
private:
	
	// maps characters to the range 0-255 in a 1-1 manner
	// remember, signed chars have value -128 to 127
	int indexFromChar(char c) 
        {
            int iFc = (int)c;
            return iFc;
	}
	
	// maps the range 0-255 into characters in a 1-1 manner
	// remember, signed chars have value -128 to 127
	char charFromIndex(int i) {
		unsigned char uc = i;
		return (char)uc;
	}
	
	// an array of 256 bools, each reresents wheter a specific
	//  character is in the set or not
	bool isInSet[NUMBER_OF_UNIQUE_CHARS];
};


////////////////////////////////////////////////////////////
//
//  TEST CODE FOR CHARSET
// 
////////////////////////////////////////////////////////////
int main() {
	
	// BEGIN TEST ONE: RANDOM NAME
	CharSet s1;
	
	// insertions galore, some duplicates
	s1.insert('B');
	s1.insert('e');
	s1.insert('n');

	s1.insert('H');
	s1.insert('e');
	s1.insert('s');
	s1.insert('c');
	s1.insert('o');
	s1.insert('t');
	s1.insert('t');
	
	// test the tostring method
	// NOTE: we output what we expect to get when testing
	cout << endl << "Expecting s1 to contains \"BHcenost\"" << endl;
	cout << "s1 actually contains     \"" << s1.toString() << "\"" << endl << endl;
	
	// test the ismember method
	cout << "Expecting: false - true - true" << endl;
	cout << "Got: "<< s1.isMember('b') << " - " << s1.isMember('e') 
		<< " - " << s1.isMember('n') << endl << endl;
	
	// BEGIN TEST TWO THE COMPLETE ALPHABET
	CharSet s2;
	
	// insert every letter in the alphabet with spaces, a period and a capital T
	s2.insert("The quick brown fox jumps over the lazy dog.");
	// remove and insert stuff to get the lowecase alphabet
	s2.remove(' ');
	s2.remove('.');
	s2.insert('t');
	s2.remove('T');
	
	// test the tostring method
	// NOTE: we output what we expect to get when testing
	cout << "Expecting s2 to contain \"abcdefghijklmnopqrstuvwxyz\"" << endl;
	cout << "s2 actually contains    \"" << s2.toString() << "\"" << endl << endl;
}
